/**********************************************************************
*  Copyright (c) 2007 - Victor Jacobs - victor.jacobs@gmail.com
*
*  Permission is hereby granted, free of charge, to any person
*  obtaining a copy of this software and associated documentation
*  files (the "Software"), to deal in the Software without
*  restriction, including without limitation the rights to use,
*  copy, modify, merge, publish, distribute, sublicense, and/or sell
*  copies of the Software, and to permit persons to whom the
*  Software is furnished to do so, subject to the following
*  conditions:
*
*  The above copyright notice and this permission notice shall be
*  included in all copies or substantial portions of the Software.
*
*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
*  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
*  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
*  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
*  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
*  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
*  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
*  OTHER DEALINGS IN THE SOFTWARE.
**********************************************************************/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Tao.OpenGl;
using Vj.ShapeLibrary;
using Vj.MathLibrary;
using Vj.BoidLibrary;

namespace Vj.BoidApp
{
    public partial class Shell : Form
    {
        public Shell()
        {
            InitializeComponent();
        }

        private Flock aFlock;
        private Flock bFlock;
        private Flock cFlock;

        private Grid floor;

        private float xRot = 0.0f;
        private float yRot = 0.0f;
        private float zRot = 0.0f;

        private double xTransFactor = 0;
        private double yTransFactor = 0;

        private double scaleFactor = 1.0;

        private Vector objectPosition;
        private Vector objectRotation;
        private Vector objectScale;
        private Vector glPerspective;

        private void simpleOpenGlControl1_Load(object sender, EventArgs e)
        {
            simpleOpenGlControl1.InitializeContexts();
            simpleOpenGlControl1.AutoSwapBuffers = true;

            objectPosition = new Vector(0.0, 0.0, 0.0);
            objectRotation = new Vector(0.0, 0.0, 0.0);
            objectScale = new Vector(1.0, 1.0, 1.0);
            glPerspective = new Vector(45.0, 0.1, 100.0);
            
            InitGL();
            SetLights();

            simpleOpenGlControl1_Resize(null, null);

            floor = new Grid(Color.FromArgb(0, 0, 25), 25, 20, false);

            aFlock = new Flock(Color.FromArgb(255, 0, 0));
            bFlock = new Flock(Color.FromArgb(255, 255, 0));
            cFlock = new Flock(Color.FromArgb(0, 255, 0));
            
            covNumericUpDown.Value = (decimal)aFlock.CenterOfMassFactor;
            dfNumericUpDown.Value = (decimal)aFlock.CenterOfVelFactor;
            avNumericUpDown.Value = (decimal)aFlock.DistanceFactor;

            yTransFactor = -50.0;
            scaleTrackBar.Value = 1;

        }

        private static bool InitGL()
        {
            //Gl.glShadeModel(Gl.GL_SMOOTH);
            Gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
            Gl.glClearDepth(1);
            Gl.glEnable(Gl.GL_DEPTH_TEST);
            Gl.glDepthFunc(Gl.GL_LEQUAL);
            Gl.glHint(Gl.GL_PERSPECTIVE_CORRECTION_HINT, Gl.GL_NICEST);
            Gl.glEnable(Gl.GL_LIGHT0);
            Gl.glEnable(Gl.GL_LIGHT1);
            Gl.glEnable(Gl.GL_LIGHTING);
            Gl.glEnable(Gl.GL_NORMALIZE);

            return true;
        }

        private void SetLights()
        {
            // global light
            float[] lmodel_ambient = { 0.75f, 0.75f, 0.75f, 1.0f };
            Gl.glLightModelfv(Gl.GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);

            float[] lightAmbient = { 0.4f, 0.4f, 0.4f, 1.0f };
            float[] lightDiffuse = { 0.6f, 0.6f, 0.6f, 1.0f };
            float[] lightPosition = { -50.0f, 20.0f, 10.0f, 1.0f };
            float[] lightPosition2 = { 50.1f, 20.0f, 10.0f, 1.0f };


            Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_POSITION, lightPosition);
            //Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_SPECULAR, lightSpecular);
            Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_AMBIENT, lightAmbient);
            Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_DIFFUSE, lightDiffuse);

            Gl.glLightfv(Gl.GL_LIGHT1, Gl.GL_POSITION, lightPosition2);
            //Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_SPECULAR, lightSpecular);
            Gl.glLightfv(Gl.GL_LIGHT1, Gl.GL_AMBIENT, lightAmbient);
            Gl.glLightfv(Gl.GL_LIGHT1, Gl.GL_DIFFUSE, lightDiffuse);
        }

        private void simpleOpenGlControl1_Resize(object sender, EventArgs e)
        {
            int w = simpleOpenGlControl1.Width;
            int h = simpleOpenGlControl1.Height;

            float ratio = ((float)w / (float)h);

            // set viewport to current window size
            Gl.glViewport(0, 0, w, h);

            // set up prespective projection
            Gl.glMatrixMode(Gl.GL_PROJECTION);
            Gl.glLoadIdentity();
            Glu.gluPerspective(90, ratio, 1, 500);
            //Glu.gluLookAt(0.0, 0.0, 30.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

            // set up model view matrix
            Gl.glMatrixMode(Gl.GL_MODELVIEW);
            Gl.glLoadIdentity();
        }

        private void simpleOpenGlControl1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
        {
            Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);
            Gl.glLoadIdentity();

            angleLabel.Text = rotationControl1.Angle.ToString();
            
            ProcessBoids();
        }

        private void xTrackBar_Scroll(object sender, EventArgs e)
        {
            //xRot = (float)xTrackBar.Value;
            //this.Refresh();
        }

        private void yTrackBar_Scroll(object sender, EventArgs e)
        {
            //yRot = (float)yTrackBar.Value;
            //this.Refresh();
        }

        private void zTrackBar_Scroll(object sender, EventArgs e)
        {
            //zRot = (float)zTrackBar.Value;
            //this.Refresh();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            //this.Refresh();
            simpleOpenGlControl1.Refresh();
        }

        private void ProcessBoids()
        {
            Gl.glPushMatrix();
            Gl.glTranslated(1.0*xTransFactor, 0.0f, 1.0*yTransFactor);

            Gl.glRotatef((xRot + yRot + zRot) % 360, xRot, yRot, zRot);

            Gl.glScaled(1.0 * scaleFactor, 1.0 * scaleFactor, 1.0 * scaleFactor);

            floor.Draw();            
            aFlock.Tick();
            bFlock.Tick();
            cFlock.Tick();

            Gl.glPopMatrix();
        }

        private void startButton_Click(object sender, EventArgs e)
        {
            timer1.Enabled = true;
        }

        private void stopButton_Click(object sender, EventArgs e)
        {
            timer1.Enabled = false;
        }

        private void covNumericUpDown_ValueChanged(object sender, EventArgs e)
        {
            aFlock.CenterOfMassFactor = (double)covNumericUpDown.Value;
            bFlock.CenterOfMassFactor = (double)covNumericUpDown.Value;
            cFlock.CenterOfMassFactor = (double)covNumericUpDown.Value;
        }

        private void dfNumericUpDown_ValueChanged(object sender, EventArgs e)
        {
            aFlock.DistanceFactor = (double)dfNumericUpDown.Value;
            bFlock.DistanceFactor = (double)dfNumericUpDown.Value;
            cFlock.DistanceFactor = (double)dfNumericUpDown.Value;
        }

        private void avNumericUpDown_ValueChanged(object sender, EventArgs e)
        {
            aFlock.CenterOfVelFactor = (double)avNumericUpDown.Value;
            bFlock.CenterOfVelFactor = (double)avNumericUpDown.Value;
            cFlock.CenterOfVelFactor = (double)avNumericUpDown.Value;
        }

        private void ResetButton_Click(object sender, EventArgs e)
        {
            timer1.Enabled = false;
            aFlock.Reset();
            bFlock.Reset();
            cFlock.Reset();
            //this.Refresh();
            simpleOpenGlControl1.Refresh();
        }

        private void scaleTrackBar_Scroll(object sender, EventArgs e)
        {
            scaleFactor = scaleTrackBar.Value;
            this.Refresh();
        }

        private void yTranslateTrackBar_Scroll(object sender, EventArgs e)
        {
            yTransFactor = yTranslationTrackBar.Value;
            this.Refresh();
        }

        private void xTranslationTrackBar_Scroll(object sender, EventArgs e)
        {
            xTransFactor = xTranslationTrackBar.Value;
            this.Refresh();

        }

        private void center2FloorcheckBox_CheckedChanged(object sender, EventArgs e)
        {
            aFlock.DrawCenter2Floor = center2FloorcheckBox.Checked;
            bFlock.DrawCenter2Floor = center2FloorcheckBox.Checked;
            cFlock.DrawCenter2Floor = center2FloorcheckBox.Checked;
        }

        private void center2OriginCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            aFlock.DrawCenter2Origin = center2OriginCheckBox.Checked;
            bFlock.DrawCenter2Origin = center2OriginCheckBox.Checked;
            cFlock.DrawCenter2Origin = center2OriginCheckBox.Checked;
        }

        private void drawVelocityCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            aFlock.DrawVelocity = drawVelocityCheckBox.Checked;
            bFlock.DrawVelocity = drawVelocityCheckBox.Checked;
            cFlock.DrawVelocity = drawVelocityCheckBox.Checked;
        }

        private void rotationControl1_MouseDown(object sender, MouseEventArgs e)
        {

        }

  



    }
}